/*
神经网络连接实现
管理神经元之间的连接权重和梯度
支持权重初始化和更新机制
*/
#include "Connection.h"
#include "Neuron.h"
#include "NeuronManager.h"
#include <random>
#include <iostream>
#include <stdexcept>

Connection::Connection(int upstreamNeuronId, int downstreamNeuronId) 
    : upstreamNeuronId(upstreamNeuronId), downstreamNeuronId(downstreamNeuronId) {
    // Initialize weights randomly
    static std::random_device rd;
    static std::mt19937 gen(rd());
    static std::uniform_real_distribution<> dis(-1.0, 1.0);
    weight = dis(gen);
    gradient = 0.0;
    setUpstreamNeuronConnection(upstreamNeuronId);
    setDownstreamNeuronConnection(downstreamNeuronId);
}
Connection::~Connection() {
    // No dynamic memory to clean up
}
const int Connection::getUpstreamNeuronId() const {
    return upstreamNeuronId;
}
const int Connection::getDownstreamNeuronId() const {
    return downstreamNeuronId;
}
const std::shared_ptr<Neuron> Connection::getUpstreamNeuron() const {
    // Retrieve the upstream neuron from NeuronManager
    return NeuronManager::getInstance().getNeuronById(upstreamNeuronId);
}
const std::shared_ptr<Neuron> Connection::getDownstreamNeuron() const {
    // Retrieve the downstream neuron from NeuronManager
    return NeuronManager::getInstance().getNeuronById(downstreamNeuronId);
}
double Connection::getWeight() const {
    return weight;
}
void Connection::setWeight(double weight) {
    if (weight < -1.0 || weight > 1.0) {
        throw std::out_of_range("Weight must be between -1.0 and 1.0");
    }
    this->weight = weight;
}
void Connection::updateWeight(double deltaWeight) { 
    double newWeight = weight + deltaWeight;
    if (newWeight < -1.0 || newWeight > 1.0) {
        throw std::out_of_range("Updated weight must be between -1.0 and 1.0");
    }
    weight = newWeight;
}
void Connection::calculateGradient() {
    // Example gradient calculation (to be replaced with actual logic)
    std::shared_ptr<Neuron> downstreamNeuron = getDownstreamNeuron();
    if (!downstreamNeuron) {
        throw std::runtime_error("Downstream neuron not found");
    }
    double downstreamDelta = downstreamNeuron->getDelta();
    std::shared_ptr<Neuron> upstreamNeuron = getUpstreamNeuron();
    if (!upstreamNeuron) {
        throw std::runtime_error("Upstream neuron not found");
    }
    double upstreamOutput = upstreamNeuron->getOutput();
    gradient = downstreamDelta * upstreamOutput;
}
double Connection::getGradient() const {
    return gradient;
}
void Connection::setGradient(double gradient) {
    this->gradient = gradient;
}
void Connection::print() const {
    std::cout << "Connection: neuron id " << upstreamNeuronId << " -> neuron id " << downstreamNeuronId << " (weight: " << weight << ", gradient: " << gradient << ")" << std::endl;
}
void Connection::setUpstreamNeuronConnection(int upstreamNeuronId) {
    std::shared_ptr<Neuron> upstreamNeuron = NeuronManager::getInstance().getNeuronById(upstreamNeuronId);
    if (!upstreamNeuron) {
        throw std::runtime_error("Upstream neuron not found");
    }
    upstreamNeuron->addDownstreamConnection(std::shared_ptr<Connection>(this));
}
void Connection::setDownstreamNeuronConnection(int downstreamNeuronId) {
    std::shared_ptr<Neuron> downstreamNeuron = NeuronManager::getInstance().getNeuronById(downstreamNeuronId);
    if (!downstreamNeuron) {
        throw std::runtime_error("Downstream neuron not found");
    }
    downstreamNeuron->addUpstreamConnection(std::shared_ptr<Connection>(this));
}